﻿/*
 *  Source code courtesy of the desktopWeb.CodePlex.com community project. See MS-PL license on Codeplex.com. 
 *  This is beta code not intended for a production application.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Activities.Statements;
using Microsoft.SharePoint.Client;
using MyData.Activities.SharePointCSOM.Caml;
using Microsoft.VisualBasic.Activities;
using System.Xml.Linq;
using System.IO;

namespace MyData.Activities
{
  public enum SharePointOperationEnum
  {
    GetItems, Update, Delete 
  }

  [Designer(typeof(MyData.Activities.Designers.SharePointItemsDesigner))]
  public sealed class SharePointItems : SharePointBaseActivity
  {
    [Browsable(false)]
    public Collection<Activity> Activities { get; set; }

    //Fields are used for updates and limit lists
    public InArgument<Dictionary<string, object>> FieldValues { get; set; }
    public InArgument<List<string>> ViewFields { get; set; }

    public OutArgument<CamlQuery> CamlQuery { get; set; }
    public OutArgument<ListItemCollection> ListItems { get; set; }

    public SharePointOperationEnum Operation { get; set; }

    private List list;

    public SharePointItems()
    {
      Activities = new Collection<Activity>();
    }

    //Cache composite activity metadata
    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
      metadata.SetChildrenCollection(Activities);
     
      base.CacheMetadata(metadata);
    }

    protected override void Execute(NativeActivityContext context)
    {
      Dictionary<string, object> fieldValues = context.GetValue(this.FieldValues);
      List<string> viewFields = context.GetValue(this.ViewFields);
      CamlQuery camlQuery = null;

      if (this.NetworkCredential.Get(context) != null)
      {
        using (ClientContext clientContext = new ClientContext(this.Url.Get(context)))
        {
          clientContext.Credentials = NetworkCredential.Get(context);

          list = clientContext.Web.Lists.GetByTitle(this.ListTitle.Get(context));

          //NEXT: CamlBuilder
          camlQuery = this.BuildCamlQuery(viewFields);  

          ListItemCollection listItems = list.GetItems(camlQuery);

          //Note: Current version does not support limiting the list to reduce payload size.
          //For example:
          //clientContext.Load(
          //      listItems,
          //      items => items.Include(
          //          item => item["Title"]));

          //Current version returns the entire schema. Limiting the schema is more efficient since the payload size is reduced
          clientContext.Load(listItems);
          clientContext.ExecuteQuery();

          ListItems.Set(context, listItems);
          CamlQuery.Set(context, camlQuery);

          if (listItems.Count > 0)
          {
            //This version only supports a Delete operation
            //See SharePointInsert activity for an insert example
            if (Operation == SharePointOperationEnum.Delete)
            {
              this.DeleteItems(listItems);

            }
            else if (Operation == SharePointOperationEnum.Update)
            {
              this.UpdateItems(listItems, fieldValues);
            }

            clientContext.ExecuteQuery();
          }
        }
      }
      else
      {
        //NOTE: Throw specific exception
      }
    }

    private CamlQuery BuildCamlQuery(List<string> viewFields)
    {
      CamlQuery camlQuery = new CamlQuery();

      camlQuery.ViewXml = new XElement(CamlElements.View,
        new XElement(CamlElements.Query,
          this.Activities.Cast<CamlWhere>()
          .Select(activity =>
            CamlElements.Where(
            activity.ComparisonOperator.ToString(),
            activity.FieldRef.Expression.ToString(),
            activity.ValueType.ToString(),
            (activity.Value.Expression as VisualBasicValue<Object>).ExpressionText.Replace("\"", string.Empty)
            )),
        new XElement(CamlElements.ViewFields,
          viewFields
          .Select(name => CamlElements.ViewFieldNames(name))),
        new XElement(CamlElements.RowLimit, 100))).ToString();

      return camlQuery;
    }

    private void DeleteItems(ListItemCollection listItems)
    {
      foreach (ListItem item in listItems.ToList())
        item.DeleteObject();
    }

    private void UpdateItems(ListItemCollection listItems, Dictionary<string, object> fieldValues)
    {
      string bdcIdentity = null;

      var bdcIdentityList = (from item in listItems[0].FieldValues where item.Key == "BdcIdentity" select item.Value);
      if (bdcIdentityList.Count() > 0)
        bdcIdentity = bdcIdentityList.First().ToString();

      ListItem specificItem = null;

      List<ListItem> items = listItems.ToList<ListItem>();

      foreach (ListItem item in items)
      {
        if (bdcIdentity == null)
        {
          this.FillItems(item, fieldValues).Update();
        }
        else
        {
          specificItem = list.GetItemById(bdcIdentity);
          this.FillItems(specificItem, fieldValues).Update();
        }
      }
    }

    private ListItem FillItems(ListItem item, Dictionary<string, object> fieldValues)
    {
      foreach (KeyValuePair<string, object> v in fieldValues)
      {
        item[v.Key] = v.Value.ToString();
      }

      return item;
    }

  }
}
